package gui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Vector;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.UIManager;

import common.Constants;

import rabid.ClusterSet;
import rabid.IndexManager;

public class RabidUI extends JFrame {
  private static final long serialVersionUID = -9142037778253811500L;

  private Dimension DEFAULT_DIM = new Dimension(100, 20);

  private IndexManager indexMgr;
  private JList lstListResults;
  private JTextArea txaTextResults;
  private JTextField txtQuery = new JTextField();
  private JScrollPane scrTextResults;
  private final int width = 500;
  private final int height = 600;
  
  public RabidUI() throws Exception {
    super("Winter Break's Rabid");
    indexMgr = new IndexManager();
  }

  /**
   * Create the GUI and show it.  For thread safety,
   * this method should be invoked from the event-dispatching thread.
   */
  public void createGui() throws IOException {

    //Create and set up the window.
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    int middleX = (int)(screenSize.getWidth() / 2 - width / 2);
    int middleY = (int)(screenSize.getHeight() / 2 - height / 2);
    setLocation(middleX, middleY);
    
    try {
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    }
    catch (Exception ex) {
      ex.printStackTrace();
    }

    //Create the user controls and displays
    txtQuery.setPreferredSize(new Dimension(200, 20));
    JButton btnQuery = new JButton("Query");
    btnQuery.setPreferredSize(DEFAULT_DIM);
    JButton btnSimilar = new JButton("Similar To");
    JButton btnDisplay = new JButton("Display");
    JButton btnIndex = new JButton("Index");
    JButton btnStats = new JButton("Stats");
    JButton btnBrowse = new JButton("Browse");
    
    JPanel pnlQuery = new JPanel();
    pnlQuery.add(txtQuery);
    pnlQuery.add(btnQuery);
    
    JPanel pnlCommands = new JPanel();
    pnlCommands.add(btnBrowse);
    pnlCommands.add(btnSimilar);
    pnlCommands.add(btnDisplay);

    lstListResults = new JList();
    JScrollPane scrListResults = new JScrollPane(lstListResults);
    scrListResults.setPreferredSize(new Dimension(180, 150));
    
    JPanel pnlCommands2 = new JPanel();
    pnlCommands2.add(btnIndex);
    pnlCommands2.add(btnStats);
        
    txaTextResults = new JTextArea();
    txaTextResults.setEditable(false);
    scrTextResults = new JScrollPane(txaTextResults);    
    scrTextResults.setPreferredSize(new Dimension(380, 400));     
    
    JButton btnQuit = new JButton("Quit");
    JPanel pnlQuit = new JPanel();
    pnlQuit.add(btnQuit);
    
    JPanel pnlMain = new JPanel();
    pnlMain.setLayout(new BoxLayout(pnlMain, BoxLayout.PAGE_AXIS));
    pnlMain.setPreferredSize(new Dimension(width, height));
    pnlMain.add(pnlQuery);
    pnlMain.add(pnlCommands);
    pnlMain.add(scrListResults);
    pnlMain.add(pnlCommands2);
    pnlMain.add(scrTextResults);
    pnlMain.add(pnlQuit);

    btnIndex.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        handlerIndex();
      }
    });

    btnStats.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        handlerStats();
      }
    });

    btnBrowse.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        handlerBrowse();
      }
    });
    
    btnSimilar.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        handlerSimilar();
      }
    });
    
    btnDisplay.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        handlerDisplay();
      }
    });
    
    btnQuery.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        handlerQuery();
      }
    });
    
    btnQuit.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        System.exit(0);
      }
    });
    
    //Display the window.
    getContentPane().add(pnlMain, BorderLayout.CENTER);
    pack();
    
  }
  
  private void handlerQuery() {
    String queryString = txtQuery.getText().toLowerCase();
    try {
      Vector queryResults = indexMgr.runQuery(queryString);
      if(queryResults.size() == 0) 
        queryResults.add("No Matches found.");
      showList(queryResults);
    }
    catch(IOException ex) {
      
    }
  }
  
  private void handlerDisplay() {
    Object selected = lstListResults.getSelectedValue();
    if(selected != null) {
      String fileName = selected.toString();
      if(indexMgr.isOutOfDate(fileName))
        showError("The file you tried to display is currently out of date with\nrespect to the corpus. You'll need a new index.", "File out of date");
      else {
        try {
          FileReader reader = new FileReader(fileName);
          StringBuffer sb = new StringBuffer();
          for(int ch = reader.read(); ch != Constants.EOF; ch = reader.read())
            sb.append((char)ch);
          txaTextResults.setText(sb.toString());
          scrTextResults.getVerticalScrollBar().setValue(0);
        }
        catch (FileNotFoundException ex) {
          showError("Could not find: "+fileName, "Display Error");
        }
        catch (IOException ex) {
          showError("An error occurred while reading the file", "File Error");
        }
      }
    }
  }
  
  private void handlerSimilar() {
    Object selected = lstListResults.getSelectedValue();
    if(selected != null) {
      String fileName = selected.toString();
      if(isFile(fileName)) {
        Vector similarFiles = indexMgr.getSimilarFiles(fileName, Constants.MAX_NUM_IN_SET);
        showList(similarFiles);        
      }
      else {
        showError("Use the BROWSE button to find files similar to the selected term", "Browse Error");
      }
    }
  }
  
  private boolean isFile(String fileName) {
    return new File(fileName).exists();
  }
  
  private void handlerIndex() {
    txaTextResults.setText(indexMgr.getIndexDetails());
  }

  private void handlerStats() {
    txaTextResults.setText(indexMgr.getCorpusDetails());    
  }

  private void handlerBrowse() {
    ClusterSet clusterSet = null;
    if(lstListResults != null) {
      Object selected = lstListResults.getSelectedValue();
      
      if(selected != null) {
        if(isFile(selected.toString())) {
          showError("You can only browse by term(s); use the DISPLAY button\nto show the contents of a file", "Browse Error");
        }
        else if(selected instanceof ClusterSet) {
          clusterSet = (ClusterSet)selected;
        }
      }
    }
    Vector clusterSets = indexMgr.browseClusterSet(clusterSet);
    showList(clusterSets);
  }
  
  private void showList(Vector list) {
    lstListResults.setListData(list);
    lstListResults.revalidate();
    lstListResults.repaint();
  }
  
  private void showError(String msg, String title) {
    JOptionPane.showMessageDialog(this, msg, title, JOptionPane.ERROR_MESSAGE);
  }

}
